/*
 * Copyright 2013 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package io.netty.channel;

import io.netty.channel.ChannelHandlerMask.Skip;
import io.netty.util.internal.InternalThreadLocalMap;

import java.util.Map;
import java.util.WeakHashMap;

/**
 * {@link ChannelHandler} 骨架实现
 */
public abstract class ChannelHandlerAdapter implements ChannelHandler {

    // 不使用 volatile, 因为它仅用于完整性检查. 标记该 channel 已经被添加进 ChannelPipeline.
    boolean added;

    /**
     * 如果 {@link ChannelHandlerAdapter#isSharable()} 返回 {@code true}, 抛出 {@link IllegalStateException}
     */
    protected void ensureNotSharable() {
        if (isSharable()) {
            throw new IllegalStateException("ChannelHandler " + getClass().getName() + " is not allowed to be shared");
        }
    }

    /**
     * 如果实现是 {@link Sharable}, 返回 {@code true}, 这样它可被添加到不同的 {@link ChannelPipeline}s.
     */
    public boolean isSharable() {
        /**
         * 缓存 {@link Sharable} 注解检测结果以解决静态条件.
         * 我们使用一个 {@link ThreadLocal} and {@link WeakHashMap} 来消除 volatile write/reads.
         * 每个 {@link Thread} 使用不同的 {@link WeakHashMap} 实例对我们来说已经足够好, 毕竟 {@link Thread} 的数量非常有限.
         *
         * See <a href="https://github.com/netty/netty/issues/2289">#2289</a>.
         */
        Class<?> clazz = getClass();
        Map<Class<?>, Boolean> cache = InternalThreadLocalMap.get().handlerSharableCache();
        Boolean sharable = cache.get(clazz);
        if (sharable == null) {
            sharable = clazz.isAnnotationPresent(Sharable.class);
            cache.put(clazz, sharable);
        }
        return sharable;
    }

    /**
     * 默认不执行任何操作, 子类可覆盖此方法.
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        // NOOP
    }

    /**
     * 默认不执行任何操作, 子类可覆盖此方法.
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        // NOOP
    }

    /**
     * Calls {@link ChannelHandlerContext#fireExceptionCaught(Throwable)} to forward
     * to the next {@link ChannelHandler} in the {@link ChannelPipeline}.
     * <p>
     * Sub-classes may override this method to change behavior.
     *
     * @deprecated is part of {@link ChannelInboundHandler}
     */
    @Skip
    @Override
    @Deprecated
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.fireExceptionCaught(cause);
    }
}
